package onslaught.core;

import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;

import javax.imageio.ImageIO;
import onslaught.model.SpriteImpl;

/**
 * A resource manager for sprites in the game. Its often quite important
 * how and where you get your game resources from. In most cases
 * it makes sense to have a central resource loader that goes away, gets
 * your resources and caches them for future use.
 * <p>
 * [singleton]
 * <p>
 * @author Kevin Glass
 */
public class Java2DSpriteStore {

   /** The single instance of this class */
   private static Java2DSpriteStore single = new Java2DSpriteStore();

   /**
    * Get the single instance of this class
    *
    * @return The single instance of this class
    */
   public static Java2DSpriteStore get() {
      return single;
   }
   /** The cached sprite map, from reference to sprite instance */
   private HashMap<String, SpriteImpl> sprites = new HashMap<String, SpriteImpl>();

   /**
    * Retrieve a sprite from the store
    *
    * @param ref The reference to the image to use for the sprite
    * @return A sprite instance containing an accelerate image of the request reference
    */
   public SpriteImpl getSprite(String ref) {
      // if we've already got the sprite in the cache
      // then just return the existing version

      if (sprites.get(ref) != null) {
         return (SpriteImpl) sprites.get(ref);
      }

      // otherwise, go away and grab the sprite from the resource
      // loader

      BufferedImage sourceImage = null;

      try {
         // The ClassLoader.getResource() ensures we get the sprite
         // from the appropriate place, this helps with deploying the game
         // with things like webstart. You could equally do a file look
         // up here.

         URL url = this.getClass().getClassLoader().getResource(ref);

         if (url == null) {
            fail("Can't find ref: " + ref);
         }

         // use ImageIO to read the image in

         sourceImage = ImageIO.read(url);
      } catch (IOException e) {
         fail("Failed to load: " + ref);
      }

      // create an accelerated image of the right size to store our sprite in

      GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
      Image image = gc.createCompatibleImage(sourceImage.getWidth(), sourceImage.getHeight(), Transparency.BITMASK);

      // draw our source image into the accelerated image

      image.getGraphics().drawImage(sourceImage, 0, 0, null);

      // create a sprite, add it the cache then return it

      SpriteImpl sprite = new SpriteImpl(image);
      sprites.put(ref, sprite);

      return sprite;
   }

   /**
    * Utility method to handle resource loading failure
    *
    * @param message The message to display on failure
    */
   private void fail(String message) {
      // we'n't available
      // we dump the message and exit the game

      System.err.println(message);
      System.exit(0);
   }
}